package com.rede.didiok.user.service.impl;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rede.didiok.common.constant.conf.MessageConf;
import com.rede.didiok.common.constant.conf.RedisConf;
import com.rede.didiok.common.constant.conf.SQLConf;
import com.rede.didiok.common.constant.conf.SysConf;
import com.rede.didiok.common.constant.global.Constants;
import com.rede.didiok.common.dto.PageInfo;
import com.rede.didiok.common.dto.user.CreditsLogDto;
import com.rede.didiok.common.dto.user.UserDto;
import com.rede.didiok.common.enums.StatusEnum;
import com.rede.didiok.common.exception.exceptionType.QueryException;
import com.rede.didiok.common.holder.RequestHolder;
import com.rede.didiok.common.utils.JsonUtils;
import com.rede.didiok.common.utils.RedisUtil;
import com.rede.didiok.common.utils.ResultUtil;
import com.rede.didiok.common.utils.StringUtils;
import com.rede.didiok.user.dao.CreditsLogDao;
import com.rede.didiok.user.entity.CreditsLogEntity;
import com.rede.didiok.user.entity.UserEntity;
import com.rede.didiok.user.service.CreditsLogService;
import com.rede.didiok.user.service.UserService;


@Service("creditsLogService")
public class CreditsLogServiceImpl extends ServiceImpl<CreditsLogDao, CreditsLogEntity> implements CreditsLogService {

    @Resource
    CreditsLogDao creditsLogDao;

    @Resource
    CreditsLogService creditsLogService;
    @Resource
    private UserService userService;
    @Resource
    RedisUtil redisUtil;

    @Override
    public String add(CreditsLogDto creditsLogVO) {
        CreditsLogEntity creditsLog = new CreditsLogEntity();
        BeanUtils.copyProperties(creditsLogVO, creditsLog, SysConf.STATUS);
        creditsLog.insert();
        return ResultUtil.successWithMessage(MessageConf.INSERT_SUCCESS);
    }

    @Override
    public Page<CreditsLogDto> queryList(PageInfo pageInfo) {
        Page page = pageInfo.creatPage();
        String requestUserUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(requestUserUid)) {
            throw new QueryException(Constants.USER_UID_EMPTY);
        }
        return creditsLogDao.queryList(page, requestUserUid);
    }

    @Override
    public void addCreditsLog(CreditsLogDto creditsLogVO) {
        creditsLogDao.addCreditsLog(creditsLogVO);
    }

    @Override
    public Page<CreditsLogDto> queryCredits(UserDto userDto) {
        Page page = userDto.creatPage();
        return creditsLogDao.queryCredits(page, userDto.getUid());
    }


    @Override
    public Integer queryCount(String userUid, Date date, String code) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        return creditsLogDao.queryCount(userUid, simpleDateFormat.format(date), code);
    }

    /**
     * 查询积分月榜
     *
     * @return
     */
    @Override
    public List<CreditsLogEntity> getLeaderMonth(Boolean refresh) {

        String rankMonthListJson = redisUtil.get(RedisConf.TOP_LIST + Constants.SYMBOL_COLON + RedisConf.TOP_MONTH_LIST);
        List<CreditsLogEntity> leaderMonth;
        if (StringUtils.isNotEmpty(rankMonthListJson) && refresh) {
            leaderMonth = JsonUtils.jsonToList(rankMonthListJson, CreditsLogEntity.class);
        } else {
            // 设置时间区间为上月初到月末
            Calendar calendar1 = Calendar.getInstance();
            calendar1.add(Calendar.MONTH, -1);
            calendar1.set(Calendar.DAY_OF_MONTH, 1);
            Date timeFirstDay = calendar1.getTime();
            //获取前一个月最后一天
            Calendar calendar2 = Calendar.getInstance();
            calendar2.set(Calendar.DAY_OF_MONTH, 0);
            Date timeLastDay = calendar2.getTime();

            QueryWrapper<CreditsLogEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("user_uid, sum(change_credits) as sumCredits ");
            queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
            queryWrapper.ge(SQLConf.CREATE_TIME, timeFirstDay);
            queryWrapper.le(SQLConf.CREATE_TIME, timeLastDay);
            queryWrapper.groupBy(SQLConf.USER_UID);
            queryWrapper.orderByDesc(SQLConf.SUM_CREDITS);
            queryWrapper.last("limit 10");
            leaderMonth = creditsLogService.list(queryWrapper);
            List<String> userIds = new ArrayList<>();
            leaderMonth.forEach((item) -> {
                userIds.add(item.getCreateUserUid());
            });
            // 获取用户列表
            Map<String, UserEntity> userMap = this.usersConvert(userIds);

            leaderMonth.forEach((item) -> {
                item.setUser(userMap.get(item.getCreateUserUid()));
            });
            redisUtil.setEx(RedisConf.TOP_LIST + Constants.SYMBOL_COLON + RedisConf.TOP_MONTH_LIST, JsonUtils.objectToJson(leaderMonth), 24, TimeUnit.HOURS);
        }
        return leaderMonth;
    }

    /**
     * 查询积分周榜
     *
     * @return
     */
    @Override
    public List<CreditsLogEntity> getLeaderWeek(Boolean refresh) {

        String rankWeekListJson = redisUtil.get(RedisConf.TOP_LIST + Constants.SYMBOL_COLON + RedisConf.TOP_WEEK_LIST);
        List<CreditsLogEntity> leaderWeek;
        if (StringUtils.isNotEmpty(rankWeekListJson) && refresh) {
            leaderWeek = JsonUtils.jsonToList(rankWeekListJson, CreditsLogEntity.class);
        } else {
            // 获取上周 周一到 周天 区间
            Calendar instance = Calendar.getInstance();
            instance.setTime(new Date());
            instance.add(Calendar.DATE, -7);
            instance.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
            instance.set(Calendar.HOUR_OF_DAY, 0);
            instance.set(Calendar.MINUTE, 0);
            instance.set(Calendar.SECOND, 0);
            //上周一日期
            Date lastMonday = instance.getTime();
            Calendar instance1 = Calendar.getInstance();
            instance1.setTime(new Date());
            instance1.add(Calendar.DATE, -1);
            instance1.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
            instance1.set(Calendar.HOUR_OF_DAY, 0);
            instance1.set(Calendar.MINUTE, 0);
            instance1.set(Calendar.SECOND, 0);
            //上周日日期
            Date lastSunday = instance1.getTime();

            QueryWrapper<CreditsLogEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("user_uid, sum(change_credits) as sumCredits ");
            queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
            queryWrapper.ge(SQLConf.CREATE_TIME, lastMonday);
            queryWrapper.le(SQLConf.CREATE_TIME, lastSunday);
            queryWrapper.groupBy(SQLConf.USER_UID);
            queryWrapper.orderByDesc(SQLConf.SUM_CREDITS);
            queryWrapper.last("limit 10");
            leaderWeek = creditsLogService.list(queryWrapper);
            List<String> userIds = new ArrayList<>();
            leaderWeek.forEach((item) -> {
                userIds.add(item.getCreateUserUid());
            });

            // 获取用户列表
            Map<String, UserEntity> userMap = this.usersConvert(userIds);

            leaderWeek.forEach((item) -> {
                item.setUser(userMap.get(item.getCreateUserUid()));
            });
            redisUtil.setEx(RedisConf.TOP_LIST + Constants.SYMBOL_COLON + RedisConf.TOP_WEEK_LIST, JsonUtils.objectToJson(leaderWeek), 24, TimeUnit.HOURS);
        }
        return leaderWeek;
    }


    /**
     * List<userIds> 转换为 Map<userId , UserEntity>
     *
     * @param userIds
     * @return
     */
    private Map<String, UserEntity> usersConvert(List<String> userIds) {
        Map<String, UserEntity> userMap = new HashMap<>();
        if (userIds.size() > 0) {
            Collection<UserEntity> collection = userService.listByIds(userIds);
            // 设置头像
            userService.setUserAvatar(collection);
            // 过滤敏感信息
            List<UserEntity> userList = userService.convertUserList(collection);
            for (UserEntity user : userList) {
                userMap.put(user.getUid(), user);
            }
        }
        return userMap;
    }


}